﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Forums.Domain
{
	using System;
	using System.Collections.Generic;
	using Falcon.Core.Authentication;
	using Falcon.Core.Collections;
	using Falcon.Core.Domain;
	using Falcon.Core.Extensions;
	using Falcon.Forums.Domain.Enums;

	public class ForumTopic : EntityBase<ForumTopic>
	{
		// private fields
		private Forum _forum;
		private ForumPost _post;
		private ForumPost _lastPost;
		private Poll _poll;
		private Log _log;

		/// <summary>
		/// Initializes a new instance of the <see cref="ForumTopic"/> class.
		/// </summary>
		public ForumTopic()
		{
			this.Identity = User.Identity;
			DeterminePermission(Roles.ForumsTopics);
		}

		/// <summary>
		/// Gets or sets the forum id.
		/// </summary>
		/// <value>The forum id.</value>
		public virtual int ForumId
		{
			get; 
			set;
		}

		/// <summary>
		/// Gets or sets the post id.
		/// </summary>
		/// <value>The post id.</value>
		public virtual int PostId
		{
			get; 
			set;
		}

		/// <summary>
		/// Gets or sets the last post id.
		/// </summary>
		/// <value>The last post id.</value>
		public virtual int LastPostId
		{
			get; 
			set;
		}

		/// <summary>
		/// Gets or sets the poll id.
		/// </summary>
		/// <value>The poll id.</value>
		public virtual int PollId
		{
			get; 
			set;
		}

		/// <summary>
		/// Gets or sets the log id.
		/// </summary>
		/// <value>The log id.</value>
		public virtual int LogId
		{
			get; 
			set;
		}

		/// <summary>
		/// Gets or sets the slug.
		/// </summary>
		/// <value>The slug.</value>
		public virtual string Slug
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the replies.
		/// </summary>
		/// <value>The replies.</value>
		public virtual int Replies
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the views.
		/// </summary>
		/// <value>The views.</value>
		public virtual int Views
		{
			get;
			set;
		}

		/// <summary>
		/// Gets a value indicating whether this instance has poll.
		/// </summary>
		/// <value><c>true</c> if this instance has poll; otherwise, <c>false</c>.</value>
		public virtual bool HasPoll
		{
			get
			{
				return this.Poll != null && this.Poll.Choices.HasValue();
			}
		}

		/// <summary>
		/// Gets a value indicating whether this instance is sticky.
		/// </summary>
		/// <value><c>true</c> if this instance is sticky; otherwise, <c>false</c>.</value>
		public virtual bool IsSticky
		{
			get
			{
				return this.Scope == ForumTopicScope.Sticky;
			}
		}

		/// <summary>
		/// Gets a value indicating whether this instance is closed.
		/// </summary>
		/// <value><c>true</c> if this instance is closed; otherwise, <c>false</c>.</value>
		public virtual bool IsClosed
		{
			get
			{
				return this.Status == ForumTopicStatus.Closed;
			}
		}

		/// <summary>
		/// Gets a value indicating whether this instance is pending.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is pending; otherwise, <c>false</c>.
		/// </value>
		public virtual bool IsPending
		{
			get
			{
				return this.Status == ForumTopicStatus.Pending;
			}
		}

		/// <summary>
		/// Gets a value indicating whether this instance is deleted.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is deleted; otherwise, <c>false</c>.
		/// </value>
		public virtual bool IsDeleted
		{
			get
			{
				return this.Status == ForumTopicStatus.Deleted;
			}
		}

		/// <summary>
		/// Gets a value indicating whether this instance is published.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is published; otherwise, <c>false</c>.
		/// </value>
		public virtual bool IsPublished
		{
			get
			{
				return this.Status == ForumTopicStatus.Published;
			}
		}

		/// <summary>
		/// Gets a value indicating whether this instance is owner.
		/// </summary>
		/// <value><c>true</c> if this instance is owner; otherwise, <c>false</c>.</value>
		public virtual bool IsOwner
		{
			get
			{
				return this.Identity != null && this.Post != null && this.Post.UserId.Equals(this.Identity.Id);
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance can update.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance can update; otherwise, <c>false</c>.
		/// </value>
		public override bool CanUpdate
		{
			get
			{
				return base.CanUpdate && this.IsOwner;
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance can delete.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance can delete; otherwise, <c>false</c>.
		/// </value>
		public override bool CanDelete
		{
			get
			{
				return base.CanDelete && this.IsOwner;
			}
		}

		/// <summary>
		/// Gets or sets the scope.
		/// </summary>
		/// <value>The scope.</value>
		public virtual ForumTopicScope Scope
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the status.
		/// </summary>
		/// <value>The status.</value>
		public virtual ForumTopicStatus Status
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the created.
		/// </summary>
		/// <value>The created.</value>
		public virtual DateTime Created
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the updated.
		/// </summary>
		/// <value>The updated.</value>
		public virtual DateTime Updated
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the forum.
		/// </summary>
		/// <value>The forum.</value>
		public virtual Forum Forum
		{
			get
			{
				return _forum;
			}
			set
			{
				_forum = value;

				if (_forum != null)
				{
					this.ForumId = _forum.Id;
				}
			}
		}

		/// <summary>
		/// Gets or sets the post.
		/// </summary>
		/// <value>The post.</value>
		public virtual ForumPost Post
		{
			get
			{
				return _post;
			}
			set
			{
				_post = value;

				if (_post != null)
				{
					this.PostId = _post.Id;
				}
			}
		}

		/// <summary>
		/// Gets or sets the last post.
		/// </summary>
		/// <value>The last post.</value>
		public virtual ForumPost LastPost
		{
			get
			{
				return _lastPost;
			}
			set
			{
				_lastPost = value;

				if (_lastPost != null)
				{
					this.LastPostId = _lastPost.Id;
				}
			}
		}

		/// <summary>
		/// Gets or sets the poll.
		/// </summary>
		/// <value>The poll.</value>
		public virtual Poll Poll
		{
			get
			{
				return _poll;
			}
			set
			{
				_poll = value;

				if (_poll != null)
				{
					this.PollId = _poll.Id;
				}
			}
		}

		/// <summary>
		/// Gets or sets the log.
		/// </summary>
		/// <value>The log.</value>
		public virtual Log Log
		{
			get
			{
				return _log;
			}
			set
			{
				_log = value;

				if (_log != null)
				{
					this.LogId = _log.Id;
				}
			}
		}

		/// <summary>
		/// Gets or sets the identity.
		/// </summary>
		/// <value>The identity.</value>
		public virtual WebUserIdentity Identity
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the tags.
		/// </summary>
		/// <value>The tags.</value>
		public virtual IList<ForumTopicTag> Tags
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the posts.
		/// </summary>
		/// <value>The posts.</value>
		public virtual IPagedList<ForumPost, ForumPostSpecification> Posts
		{
			get; 
			set;
		}

		/// <summary>
		/// Updates the replies.
		/// </summary>
		public virtual void UpdateReplies()
		{
			UpdateReplies(1, true);
		}

		/// <summary>
		/// Updates the replies.
		/// </summary>
		/// <param name="value">The value.</param>
		/// <param name="addition">if set to <c>true</c> [addition].</param>
		public virtual void UpdateReplies(int value, bool addition)
		{
			if (addition)
			{
				this.Replies = this.Replies + value;
			}
			else
			{
				this.Replies = this.Replies - value;
			}
		}

		/// <summary>
		/// Updates the views.
		/// </summary>
		public virtual void UpdateViews()
		{
			UpdateViews(1, true);
		}

		/// <summary>
		/// Updates the views.
		/// </summary>
		/// <param name="value">The value.</param>
		/// <param name="addition">if set to <c>true</c> [addition].</param>
		public virtual void UpdateViews(int value, bool addition)
		{
			if (addition)
			{
				this.Views = this.Views + value;
			}
			else
			{
				this.Views = this.Views - value;
			}
		}

		/// <summary>
		/// Validates this instance.
		/// </summary>
		public override void Validate()
		{
			this.Rules().Validate(this);
		}
	}
}